import hashlib
import json
import uuid
from datetime import datetime

from django.http import JsonResponse
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods

from .models import User, Content
from .modules.ExceptionPrinter import printException
from .modules.Macros import *

hl = hashlib.md5()


def md5uuid():
	hl.update(str(uuid.uuid1()).encode('utf-8'))
	return hl.hexdigest()


def getJsonContent(request):
	if request.body.decode('utf-8') == "":
		return {}
	data = request.body.decode('utf-8')
	return json.loads(data)


def decorateParamValid(response):
	response[DBTags.STATUS] = STATUS.FAILED
	response[DBTags.REASON] = DBStatus.ParamInvalid
	return response


def decorateUndefinedError(response, e):
	response[DBTags.STATUS] = STATUS.FAILED
	response[DBTags.REASON] = str(e)
	return response


def str2datetime(timeStr):
	dt = datetime.strptime(timeStr, "%Y/%m/%d %H:%M:%S %z")
	return dt.replace(tzinfo=timezone.get_current_timezone())


# @require_http_methods(['GET'])
def signUp(request):
	params = getJsonContent(request)

	response = {
		DBTags.ACTION: ACTIONS.SIGNUP
	}
	try:
		account = params[DBTags.ACCOUNT]
		nickname = params[DBTags.NICKNAME]
		password = params[DBTags.PASSWORD]
	except KeyError:
		return JsonResponse(decorateParamValid(response))

	try:
		user = User.objects.get(account__exact=account)
		response[DBTags.STATUS] = STATUS.FAILED
		response[DBTags.REASON] = DBStatus.AccountAlreadyExisted
		return JsonResponse(response)
	except User.DoesNotExist:
		try:
			user = User()
			user.account = account
			user.nickname = nickname
			user.password = password.lower()
			user.uid = md5uuid()
			user.createTime = datetime.now(tz=timezone.get_current_timezone())
			user.save()
			response[DBTags.STATUS] = STATUS.SUCCESSFUL
		except Exception as e:
			printException(e)
			response[DBTags.STATUS] = STATUS.FAILED
			response[DBTags.REASON] = str(e)
		finally:
			return JsonResponse(response)


# @require_http_methods(['GET'])
def login(request):
	params = getJsonContent(request)
	response = {
		DBTags.ACTION: ACTIONS.LOGIN
	}
	try:
		account = params[DBTags.ACCOUNT]
		password = params[DBTags.PASSWORD]
	except KeyError:
		return JsonResponse(decorateParamValid(response))

	try:
		user = User.objects.get(account__exact=account)
		if user.password.lower() == password.lower():
			response[DBTags.STATUS] = STATUS.SUCCESSFUL
			response[DBTags.UID] = user.uid
			response[DBTags.NICKNAME] = user.nickname
			response[DBTags.ACCOUNT] = user.account
		else:
			response[DBTags.STATUS] = STATUS.FAILED
			response[DBTags.REASON] = DBStatus.AccountNotExistOrWrongPassword
	except User.DoesNotExist:
		response[DBTags.STATUS] = STATUS.FAILED
		response[DBTags.REASON] = DBStatus.AccountNotExistOrWrongPassword
	except Exception as e:
		printException(e)
		response = decorateUndefinedError(response, e)
	finally:
		return JsonResponse(response)


# @require_http_methods("GET")
def push(request):
	params = getJsonContent(request)
	response = {
		DBTags.ACTION: ACTIONS.PUSH
	}
	try:
		uid = params[DBTags.UID]
		content = params[DBTags.CONTENT]
		time = params[DBTags.TIME]
		device = params[DBTags.DEVICE]
	except KeyError:
		return JsonResponse(decorateParamValid(response))

	try:
		user = User.objects.get(uid__exact=uid)
		cid = md5uuid()
		contentItem = Content()
		contentItem.user = user
		contentItem.cid = cid
		contentItem.content = content
		contentItem.time = str2datetime(time)
		contentItem.read = False
		contentItem.device = device

		contentItem.save()
		response[DBTags.STATUS] = STATUS.SUCCESSFUL
		response[DBTags.CID] = cid
		response[DBTags.UID] = uid
	except User.DoesNotExist:
		response[DBTags.STATUS] = STATUS.FAILED
		response[DBTags.REASON] = DBStatus.AccountNotExistOrWrongPassword
	except Exception as e:
		printException(e)
		response = decorateUndefinedError(response, e)
	finally:
		return JsonResponse(response)


# @require_http_methods("GET")
def query(request):
	params = getJsonContent(request)
	response = {
		DBTags.ACTION: ACTIONS.QUERY
	}
	try:
		uid = params[DBTags.UID]
		start = params[DBTags.START]
		count = params[DBTags.COUNT]
	except KeyError:
		return JsonResponse(decorateParamValid(response))

	try:
		user = User.objects.get(uid__exact=uid)
		contentSet = Content.objects.filter(user__exact=user).order_by('-time')[start:start+count]

		pack = []
		for content in contentSet:
			data = {
				DBTags.CID: content.cid,
				DBTags.CONTENT: content.content[0:30],
				DBTags.READ: content.read
			}
			pack.append(data)
		response[DBTags.STATUS] = STATUS.SUCCESSFUL
		response[DBTags.START] = start
		response[DBTags.COUNT] = len(pack)
		response[DBTags.ITEMS] = pack
	except User.DoesNotExist:
		response[DBTags.STATUS] = STATUS.FAILED
		response[DBTags.REASON] = DBStatus.AccountNotExistOrWrongPassword
	except Exception as e:
		printException(e)
		response = decorateUndefinedError(response, e)
	finally:
		return JsonResponse(response)


# @require_http_methods(['GET'])
def fetch(request):
	params = getJsonContent(request)
	response = {
		DBTags.ACTION: ACTIONS.FETCH
	}
	try:
		cid = params[DBTags.CID]
	except KeyError:
		return JsonResponse(decorateParamValid(response))

	try:
		contentItem = Content.objects.get(cid__exact=cid)

		response[DBTags.CID] = contentItem.cid
		response[DBTags.CONTENT] = contentItem.content
		response[DBTags.TIME] = contentItem.time
		response[DBTags.READ] = contentItem.read
		response[DBTags.DEVICE] = contentItem.device
		response[DBTags.STATUS] = STATUS.SUCCESSFUL

	except Exception as e:
		printException(e)
		decorateUndefinedError(response, e)
	finally:
		return JsonResponse(response)


# @require_http_methods(['GET'])
# @csrf_exempt
def alive(request):
	response = {
		DBTags.ACTION: ACTIONS.ALIVE,
		DBTags.STATUS: STATUS.SUCCESSFUL
	}
	return JsonResponse(response)


# @require_http_methods(['GET'])
def read(request):
	params = getJsonContent(request)
	response = {
		DBTags.ACTION: ACTIONS.READ
	}
	try:
		cid = params[DBTags.CID]
	except KeyError:
		decorateParamValid(response)

	try:
		content = Content.objects.get(cid__exact=cid)
		content.read = True
		content.save()
		response[DBTags.STATUS] = STATUS.SUCCESSFUL
	except Exception as e:
		printException(e)
		decorateUndefinedError(response, e)
	finally:
		return JsonResponse(response)
